﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data;
using System.Data.Common;

using Ice.Toolkit.Data.Entity;
using Ice.Toolkit.Data.ILInvoker;

namespace Ice.Toolkit.Data
{
    /// <summary>
    /// 构造实体生成器
    /// </summary>
    /// <typeparam name="T">实体类型,必须继承EntityBase</typeparam>
    public class EntityBuilder<T> where T : EntityBase<T>, new()
    {
        protected IDataReader DataRead { get; set; }

        protected List<KeyValuePair<String, EntityColumn>> Columns { get; set; }

        public EntityBuilder(IDataReader dataReader)
        {
            DataRead = dataReader;
            Columns = EntityAttribManager.Get<T>().Columns;
        }
        /// <summary>
        /// 创建一个新的实体类对像
        /// </summary>
        /// <returns></returns>
        public List<T> CreateInstances()
        {
            List<T> instances = new List<T>();

            while (DataRead.Read())
            {
                T entity = new T();
                Type et = typeof(T);

                foreach (var item in Columns)
                {
                    var index = DataRead.GetOrdinal(item.Value.DbColumn);

                    et.GetProperty(item.Key).SetValue(entity, DataRead.GetValue(index), null);
                    //效率低未用,未知原因
                    //PropertyAccessor<T>.Set(entity, item.Key, DataRead.GetValue(index));
                    //效率低未用,原因可能是未设置缓存，每次生成一个表达式，在负值。
                    //CreateSetPropertyValueAction(item.Key)(entity, DataRead.GetValue(index));
                }

                instances.Add(entity);
            }

            return instances;
        }
        /// <summary>
        /// 创建一个对属性负值的Lambda表达式
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static Action<T, object> CreateSetPropertyValueAction(string name)
        {
            var property = typeof(T).GetProperty(name);
            var target = Expression.Parameter(typeof(object));
            var propertyValue = Expression.Parameter(typeof(object));
            var castTarget = Expression.Convert(target, typeof(T));
            var castPropertyValue = Expression.Convert(propertyValue, property.PropertyType);
            var setPropertyValue = Expression.Call(castTarget, property.GetSetMethod(), castPropertyValue);
            return Expression.Lambda<Action<T, object>>(setPropertyValue, target, propertyValue).Compile();
        }
    }
}
